package com.vcc.web.controller;

import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaCheckSafe;
import cn.hutool.core.util.IdUtil;
import com.mybatisflex.core.paginate.Page;
import com.vcc.channel.base.model.request.TransferDto;
import com.vcc.channel.base.service.ChannelBaseService;
import com.vcc.core.annotations.RepeatSubmit;
import com.vcc.core.annotations.RestPack;
import com.vcc.core.exception.NotFoundException;
import com.vcc.data.entity.*;
import com.vcc.service.client.share.account.request.ClientShareAccountTransferRequest;
import com.vcc.service.client.share.account.request.ClientShareAccountUpdateRequest;
import com.vcc.service.client.share.account.response.ClientShareAccountResponse;
import com.vcc.service.client.share.detail.response.ClientShareAccountDetailResponse;
import com.vcc.service.client.share.order.response.ClientShareAccountOrderResponse;
import com.vcc.service.service.*;
import com.vcc.web.core.util.UserUtil;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.List;

@RestController
@RequestMapping("shareAccount")
public class ShareAccountController {


    @Resource
    private ShareAccountOrderService shareAccountOrderService;
    @Resource
    private ShareAccountService shareAccountService;
    @Resource
    private UserService userService;
    @Resource
    private ApplicationContext applicationContext;
    @Autowired
    private ChannelService channelService;
    @Autowired
    private CardTypeService cardTypeService;
    @Autowired
    private WalletService walletService;
    @Autowired
    private WalletDetailService walletDetailService;
    @Autowired
    private ShareAccountDetailService shareAccountDetailService;


    @SaCheckLogin
    @RestPack
    @PostMapping("request")
    @RepeatSubmit
    @SaCheckPermission("client:shareAccount:request")
    public boolean request() {
        return shareAccountOrderService.createShareAccountOrder(UserUtil.getId(), null);
    }


    @SaCheckLogin
    @RestPack
    @GetMapping("orderPaging")
    @SaCheckPermission("client:shareAccount:order:view")
    public Page<ClientShareAccountOrderResponse> orderPaging(Integer pageNumber, Integer pageSize, Integer status) {
        return shareAccountOrderService.paging(pageNumber, pageSize, UserUtil.getId(), status);
    }


    @SaCheckLogin
    @RestPack
    @GetMapping("accountPaging")
    @SaCheckPermission("client:shareAccount:view")
    public Page<ClientShareAccountResponse> accountPaging(Integer pageNumber, Integer pageSize, Long targetUserId, String name) {
        Role role = UserUtil.getRole();
        User user = UserUtil.get();
        if (targetUserId != null && !role.getHasAllData()) {
            UserUtil.baseVerifyUser(
                    role,
                    user.getId(),
                    targetUserId,
                    user.getParentId(),
                    userService.getParentIdById(targetUserId)
            );
        }
        return shareAccountService.paging(
                pageNumber,
                pageSize,
                role,
                user.getId(),
                targetUserId,
                name,
                null
        ).map(it -> {
            ChannelBaseService channelBaseService = applicationContext.getBean(it.getChannelCode(), ChannelBaseService.class);
            BigDecimal balance = channelBaseService.queryAccountBalance(it.getAccountId());
            it.setBalance(balance);
            it.setAccountId("");
            it.setChannelCode("");
            return it;
        });
    }


    @SaCheckLogin
    @RestPack
    @PostMapping("update")
    @SaCheckPermission("client:shareAccount:edit")
    public boolean update(@RequestBody @Validated ClientShareAccountUpdateRequest clientShareAccountUpdateRequest) {
        ShareAccount shareAccount = shareAccountService.getByIdOpt(clientShareAccountUpdateRequest.getId()).orElseThrow(() -> new NotFoundException("共享账号不存在"));
        UserUtil.baseVerifyUser(
                UserUtil.getRole(),
                UserUtil.getId(),
                shareAccount.getUserId(),
                UserUtil.get().getParentId(),
                userService.getParentIdById(shareAccount.getUserId())
        );
        shareAccountService.updateName(
                clientShareAccountUpdateRequest.getId(),
                clientShareAccountUpdateRequest.getAccountName()
        );
        return true;
    }


    @SaCheckLogin
    @RestPack
    @GetMapping("listAll")
    @SaCheckPermission("client:shareAccount:view")
    public List<ClientShareAccountResponse> listAll(Long cardId) {
        Role role = UserUtil.getRole();
        User user = UserUtil.get();
        CardType cardType = cardTypeService.getById(cardId);
        Channel channel = channelService.getByCode(cardType.getChannelName());
        if (!channel.getHasShareAccount()) {
            throw new NotFoundException("该渠道不支持共享账号");
        }
        ChannelBaseService channelBaseService = applicationContext.getBean(channel.getCode(), ChannelBaseService.class);

        return shareAccountService.list(
                user.getId(),
                channel.getCode()
        ).stream().peek(it -> {
            BigDecimal balance = channelBaseService.queryAccountBalance(it.getAccountId());
            it.setBalance(balance);
            it.setAccountId("");
            it.setChannelCode("");
        }).toList();
    }


    @SaCheckLogin
    @RestPack
    @GetMapping("detailPaging")
    @SaCheckPermission("client:shareAccount:detail:view")
    public Page<ClientShareAccountDetailResponse> detailPaging(
            Integer pageNumber,
            Integer pageSize,
            String orderId,
            Long shareAccountId,
            String type,
            String startDate,
            String endDate
    ) {
        Role role = UserUtil.getRole();
        User user = UserUtil.get();
        ShareAccount shareAccount = shareAccountService.getByIdOpt(shareAccountId).orElseThrow(() -> new NotFoundException("共享账号不存在"));
        UserUtil.baseVerifyUser(
                role,
                user.getId(),
                shareAccount.getUserId(),
                user.getParentId(),
                userService.getParentIdById(shareAccount.getUserId())
        );
        return shareAccountDetailService.paging(
                pageNumber,
                pageSize,
                orderId,
                shareAccountId,
                type,
                startDate,
                endDate
        );
    }


    @SaCheckLogin
    @RestPack
    @PostMapping("transfer")
    @SaCheckPermission("client:shareAccount:transfer")
    @SaCheckSafe("SHARE_TRANSFER")
    @RepeatSubmit
    public boolean transfer(@RequestBody @Validated ClientShareAccountTransferRequest request) {
        Role role = UserUtil.getRole();
        User user = UserUtil.get();
        ShareAccount shareAccount = shareAccountService.getByIdOpt(request.getId()).orElseThrow(() -> new NotFoundException("共享账号不存在"));
        UserUtil.baseVerifyUser(
                role,
                user.getId(),
                shareAccount.getUserId(),
                user.getParentId(),
                userService.getParentIdById(shareAccount.getUserId())
        );
        ChannelBaseService channelBaseService = applicationContext.getBean(shareAccount.getChannelCode(), ChannelBaseService.class);
        Wallet wallet = walletService.getByUserIdAndCurrencyCode(shareAccount.getUserId(), "USD");
        String requestId = IdUtil.getSnowflakeNextIdStr();

        if (wallet == null) {
            throw new NotFoundException("用户钱包不存在");
        }
        //true 主转子  false 子转主
        if (request.getHasTransferIn()) {
            BigDecimal mainBalance = channelBaseService.queryAccountBalance();
            if (mainBalance.compareTo(request.getAmount()) < 0) {
                throw new NotFoundException("主账户余额不足");
            }

            if (wallet.getUsableQuota().compareTo(request.getAmount()) < 0) {
                throw new NotFoundException("用户资金钱包余额不足");
            }
            BigDecimal walletBalance = walletService.subtractUsableQuotaById(
                    wallet.getId(),
                    request.getAmount(),
                    2,
                    false
            );
            walletDetailService.shareAccountRecharge(
                    shareAccount.getId(),
                    requestId,
                    shareAccount.getAccountName() + "共享账户充值",
                    request.getAmount(),
                    walletBalance,
                    wallet.getCurrencyId(),
                    shareAccount.getUserId()
            );
            TransferDto transferDto = new TransferDto();
            transferDto.setAccountId(shareAccount.getAccountId());
            transferDto.setAmount(request.getAmount());
            transferDto.setType("transfer_in");
            Boolean transfer = channelBaseService.transfer(transferDto);
            if (!transfer) {
                walletDetailService.accountRecharge(
                        "R" + requestId,
                        "原共享账户充值订单" + requestId + "失败，退回钱包",
                        request.getAmount(),
                        walletBalance,
                        wallet.getCurrencyId(),
                        shareAccount.getUserId()
                );
                throw new NotFoundException("转账失败");
            } else {
                shareAccountDetailService.create(
                        shareAccount.getId(),
                        channelBaseService.queryAccountBalance(shareAccount.getAccountId()),
                        wallet.getCurrencyCode(),
                        shareAccount.getChannelCode(),
                        "TRANSFER_IN",
                        requestId,
                        request.getAmount(),
                        "用户资金钱包转入共享账户",
                        true,
                        null,
                        null,
                        shareAccount.getUserId(),
                        UserUtil.getId()
                );
            }
        } else {
            BigDecimal shareBalance = channelBaseService.queryAccountBalance(shareAccount.getAccountId());
            if (shareBalance.compareTo(request.getAmount()) < 0) {
                throw new NotFoundException("共享账户余额不足");
            }
            TransferDto transferDto = new TransferDto();
            transferDto.setAccountId(shareAccount.getAccountId());
            transferDto.setAmount(request.getAmount());
            transferDto.setType("transfer_out");
            Boolean transfer = channelBaseService.transfer(transferDto);
            if (!transfer) {
                throw new NotFoundException("转账失败");
            } else {
                shareAccountDetailService.create(
                        shareAccount.getId(),
                        channelBaseService.queryAccountBalance(shareAccount.getAccountId()),
                        "USD",
                        shareAccount.getChannelCode(),
                        "TRANSFER_OUT",
                        requestId,
                        request.getAmount(),
                        "共享账户转出到用户资金钱包",
                        false,
                        null,
                        null,
                        shareAccount.getUserId(),
                        UserUtil.getId()
                );
                BigDecimal walletBalance = walletService.addUsableQuotaById(
                        wallet.getId(),
                        request.getAmount(),
                        1,
                        false
                );
                walletDetailService.shareAccountWithdraw(
                        shareAccount.getId(),
                        requestId,
                        "共享账户转出到用户资金钱包",
                        request.getAmount(),
                        walletBalance,
                        wallet.getCurrencyId(),
                        shareAccount.getUserId()
                );
            }
        }
        return true;
    }

}
